﻿/**************************************************************************
创建日期:	2014/1/13
作	  者:	张存
邮 	  箱:	zhangcunliang@126.com
创建时间:	
Copyright (c)    ZhCun.cn

描	述：
记	录：
    2020.2.23 
        修改数据源为object类型，
        增加输入即查询的实现，改数据源为object，同时支持List与DataTable
    2020.3.9  增加列信息的几个属性
    2020.3.16 当tag不为空时，不允许输入内容的bug修复
***************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZhCun.Utils.Helpers;
using ZhCun.Win.Controls;

namespace ZhCun.Win.Extend
{
    /// <summary>
    /// comboxGrid 列信息
    /// </summary>
    public class ComboxGridColumn
    {
        /// <summary>
        /// 默认构造
        /// </summary>
        public ComboxGridColumn()
        { }
        /// <summary>
        /// 初始化GridColumn
        /// </summary>
        public ComboxGridColumn(string fieldName, string caption, bool isVisible = true)
        {
            ColumnFiled = fieldName;
            ColumnCaption = caption;
            IsVisible = isVisible;
        }
        /// <summary>
        /// 列标题
        /// </summary>
        public string ColumnCaption { set; get; }
        /// <summary>
        /// 字段名
        /// </summary>
        public string ColumnFiled { set; get; }
        /// <summary>
        /// 是否显示
        /// </summary>
        public bool IsVisible { set; get; } = true;
        /// <summary>
        /// 列宽
        /// </summary>
        public int ColumnWidth { get; set; } = 0;
        /// <summary>
        /// 列显示格式化
        /// </summary>
        public string ColumnFormat { set; get; }
        /// <summary>
        /// 对齐方式
        /// </summary>
        public DataGridViewContentAlignment Alignment { set; get; }
        /// <summary>
        /// 大小模式
        /// </summary>
        public DataGridViewAutoSizeColumnMode AutoSizeMode { set; get; }
        /// <summary>
        /// 列控件类型
        /// </summary>
        public DgvColumnType ColumnType { set; get; }
    }

    /// <summary>
    /// ComboxGrid 参数对象
    /// </summary>
    public class ComboxGridArgs
    {
        /// <summary>
        /// 文本框控件
        /// </summary>
        public EditText TxtBox { set; get; }
        /// <summary>
        /// 列信息
        /// </summary>
        public ComboxGridColumn[] Columns { set; get; }
        /// <summary>
        /// 返回文本框文本的字段
        /// </summary>
        public string ReturnTextField { set; get; }
        /// <summary>
        /// 返回文本框Tag的字段
        /// </summary>
        public string RetrunTagField { set; get; }
        /// <summary>
        /// 获取数据源的方法
        /// </summary>
        public Func<string, object> GetDataSourceHandle { set; get; }
        /// <summary>
        /// GridView  最多显示的行数，默认为 10
        /// </summary>
        public int MaxRowCount { set; get; } = 10;
        /// <summary>
        /// 当只有一行数据时是否自动选择退出（默认为true）
        /// </summary>
        public bool IsAutoSelected { set; get; } = true;
        /// <summary>
        /// 是否回车才开始查询显示数据（默认为true）
        /// </summary>
        public bool IsAnyKeyShow { set; get; } = false;
        /// <summary>
        /// 当非回车显示时，文本中内容最小值是多少才进行搜索显示（默认为0）
        /// </summary>
        public int KeyPressMinlength { set; get; } = 0;
        /// <summary>
        /// 当选中节点后是否自动响应Tab按键，焦点到下一个TabIdnex（默认为true）
        /// </summary>
        public bool IsSendTabKey { set; get; } = true;
        /// <summary>
        /// gridview 的自动大小列模式
        /// </summary>
        public DataGridViewAutoSizeColumnsMode AutoSizeColumnsMode { get; internal set; }

        /// <summary>
        /// 坐标是否变化的临时变量
        /// </summary>
        internal bool LocationChanged { set; get; } = false;
    }

    /// <summary>
    /// 下拉列表的GridView 实现,替换 ComboxList 的实现
    /// </summary>
    public class ComboxGrid
    {
        readonly Dictionary<EditText, ComboxGridArgs> CGArgDict = new Dictionary<EditText, ComboxGridArgs>();

        /// <summary>
        /// 当前控件使用的GridView
        /// </summary>
        public GridView GridView { get; private set; }

        ///// <summary>
        ///// 按回车选择行之后的事件
        ///// </summary>
        //[Obsolete("请使用 OnSelectedRowItem 事件 2020.2.23")]
        //public event Action<EditText, DataRow> OnSelectedRow;
        /// <summary>
        /// 按回车选择行之后的事件,参数为实体对象或者DataRow,此事件替代 OnSelectedRow
        /// </summary>
        public event Action<EditText, object> OnSelectedRowItem;
        /// <summary>
        /// 在显示GridView之前出发的事件
        /// </summary>
        public event Action<ComboxGridArgs> OnBeforeShowGridView;

        bool _IsInput = false;

        /// <summary>
        /// 初始化GridView, GridView为空才显示
        /// </summary>
        void InitGridView()
        {
            if (GridView == null)
            {
                GridView = new GridView();
                GridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
                GridView.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal;
                GridView.ScrollBars = ScrollBars.None;
                GridView.RowHeadersVisible = false;
                GridView.DisplayRowNo = false;
                //GridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
                GridView.MouseDoubleClick += (s, e) =>
                {
                    SelectedRowHandle();
                };
                GridView.KeyDown += (s, e) =>
                {
                    if (e.KeyCode == Keys.Enter)
                    {
                        SelectedRowHandle();
                    }
                    if (e.KeyCode == Keys.Escape)
                    {
                        var tb = GridView.Tag as TextBox;
                        GridView.Visible = false;
                        tb.Focus();
                        tb.SelectionStart = tb.Text.Length;
                    }
                };
            }
        }
        /// <summary>
        /// 注册文本框的事件
        /// </summary>
        void RegisterTextBoxEvent(EditText txtBox)
        {
            txtBox.Enter -= TxtBox_Enter;
            txtBox.Enter += TxtBox_Enter;
            //txtBox.KeyUp += new KeyEventHandler(txtBox_KeyUp);
            //keyPress是在keydown之后触发,所以在keyDown绑定数据源,keyPress显示Grid
            txtBox.KeyPress -= TxtBox_KeyPress;
            txtBox.KeyPress += TxtBox_KeyPress;

            //txtBox.KeyDown -= TxtBox_KeyDown;
            //txtBox.KeyDown += TxtBox_KeyDown;

            txtBox.KeyUp -= TxtBox_KeyUp;
            txtBox.KeyUp += TxtBox_KeyUp;

            txtBox.TextChanged -= TxtBox_TextChanged;
            txtBox.TextChanged += TxtBox_TextChanged;

            txtBox.Leave -= TxtBox_Leave;
            txtBox.Leave += TxtBox_Leave;

            txtBox.LocationChanged -= TxtBox_LocationChanged;
            txtBox.LocationChanged += TxtBox_LocationChanged;
        }
        /// <summary>
        /// 当坐标改变后,重新设置Grid的位置
        /// </summary>
        private void TxtBox_LocationChanged(object sender, EventArgs e)
        {
            var ctr = sender as EditText;
            if (CGArgDict.ContainsKey(ctr))
            {
                var arg = CGArgDict[ctr];
                arg.LocationChanged = true;
            }
        }

        /// <summary>
        /// 离开焦点，设置 _IsInput = false
        /// </summary>
        void TxtBox_Leave(object sender, EventArgs e)
        {
            _IsInput = false;
        }
        /// <summary>
        /// 当文本内容改变时，判断Tag有值，则按不允许录入文本处理（清空Tag与Text）
        /// </summary>
        void TxtBox_TextChanged(object sender, EventArgs e)
        {
            if (!_IsInput) return;
            var tb = (EditText)sender;
            var arg = CGArgDict[tb];
            if (tb.ValueItem != null && !arg.RetrunTagField.IsEmpty())
            {
                tb.ValueItem = null;
                tb.Text = string.Empty;
            }
            //if (tb.Tag != null && !arg.RetrunTagField.IsEmpty())
            //{
            //    tb.Tag = null;
            //    tb.Text = string.Empty;
            //}
        }
        /// <summary>
        /// 键盘抬起，实现按任意键查询等功能
        /// </summary>
        void TxtBox_KeyUp(object sender, KeyEventArgs e)
        {
            var tb = (EditText)sender;
            var arg = CGArgDict[tb];

            if (e.KeyCode != Keys.Enter && arg.IsAnyKeyShow && tb.TextLength > arg.KeyPressMinlength)
            {
                if ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.Divide) || e.KeyCode == Keys.Back)
                {
                    ShowGridView(tb);
                }
            }
            if (e.KeyCode == Keys.Down && GridView.Visible)
            {
                GridView.Rows[0].Selected = true;
                GridView.Focus();
            }
        }
        /// <summary>
        /// 显示GridView
        /// </summary>
        void TxtBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            _IsInput = true;
            var tb = (EditText)sender;
            if (e.KeyChar == (char)Keys.Enter)
            {
                ShowGridView(tb);
            }

            if (e.KeyChar == (char)Keys.Escape)
            {
                GridView.Visible = false;
            }
        }
        /// <summary>
        /// 获得焦点时将DataGridView隐藏
        /// </summary>
        void TxtBox_Enter(object sender, EventArgs e)
        {
            if (GridView != null && GridView.Tag != sender)
            {
                GridView.Visible = false;
            }
        }
        /// <summary>
        /// 选中行后的处理方法
        /// </summary>
        void SelectedRowHandle()
        {
            var selItem = GridView.GetSelectedItemData();
            var tb = GridView.Tag as EditText;
            SelectedRowHandle(tb, selItem);
        }
        /// <summary>
        /// 选中行之后的处理
        /// </summary>
        void SelectedRowHandle(EditText tb, object selItem)
        {
            _IsInput = false;
            var txtArg = CGArgDict[tb];
            GridView.Visible = false;
            if (!string.IsNullOrEmpty(txtArg.RetrunTagField))
            {
                tb.ValueItem = ReflectionHelper.GetPropertyValue(selItem, txtArg.RetrunTagField);
                //tb.Tag = ReflectionHelper.GetPropertyValue(selItem, txtArg.RetrunTagField);
            }
            if (!string.IsNullOrWhiteSpace(txtArg.ReturnTextField))
            {
                var r = ReflectionHelper.GetPropertyValue(selItem, txtArg.ReturnTextField);
                tb.Text = r?.ToString();
            }
            //_IsInput = true;
            tb.Focus();
            if (txtArg.IsSendTabKey)
            {
                SendKeys.Send("{Tab}");
            }

            OnSelectedRowItem?.Invoke(tb, selItem);
        }
        /// <summary>
        /// 取得顶点相对位置横坐标
        /// </summary>
        int GetLeft(Control crl)
        {
            if (crl.Parent is Form)
            {
                return crl.Left;
            }
            else
            {
                return crl.Left + GetLeft(crl.Parent);
            }
        }
        /// <summary>
        /// 取得顶点相对位置纵坐标
        /// </summary>
        int GetTop(Control crl)
        {
            if (crl.Parent is Form)
            {
                return crl.Top;
            }
            else
            {
                return crl.Top + GetTop(crl.Parent);
            }
        }
        /// <summary>
        /// 显示GridView到指定坐标，并加载数据源
        /// </summary>
        void ShowGridView(EditText tb)
        {
            if (!CGArgDict.ContainsKey(tb))
            {
                return;
            }
            var txtArg = CGArgDict[tb];

            OnBeforeShowGridView?.Invoke(txtArg);

            var data = txtArg.GetDataSourceHandle?.Invoke(tb.Text);
            int dataCount = 0;

            if (data != null)
            {
                if (data is IList rList)
                {
                    dataCount = rList.Count;
                    if (txtArg.IsAutoSelected && dataCount == 1)
                    {
                        SelectedRowHandle(tb, rList[0]);
                        return;
                    }
                }
                else if (data is DataTable rTable)
                {
                    dataCount = rTable.Rows.Count;
                    if (txtArg.IsAutoSelected && dataCount == 1)
                    {
                        SelectedRowHandle(tb, rTable.Rows[0]);
                        return;
                    }
                }
                else
                {
                    throw new NotImplementedException("不支持绑定的数据类型，仅支持List与DataTable");
                }
            }

            if (dataCount == 0)
            {
                GridView.Visible = false;
                return;
            }

            if (GridView.Tag != tb)
            {
                GridView.DataSource = null;
                //重新生成列
                GridView.Columns.Clear();
                GridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

                if (txtArg.AutoSizeColumnsMode != 0 && txtArg.AutoSizeColumnsMode != DataGridViewAutoSizeColumnsMode.None)
                {
                    GridView.AutoSizeColumnsMode = txtArg.AutoSizeColumnsMode;
                }
                else
                {
                    GridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
                }

                foreach (var item in txtArg.Columns)
                {
                    var dgvCol = GridView.CreateColumn(item.ColumnType, item.ColumnCaption, item.ColumnFiled);

                    dgvCol.Visible = item.IsVisible;
                    dgvCol.DefaultCellStyle.Format = item.ColumnFormat;

                    if (!item.ColumnFormat.IsEmpty())
                    {
                        dgvCol.DefaultCellStyle.Format = item.ColumnFormat;
                    }
                    if (item.ColumnWidth > 0)
                    {
                        dgvCol.Width = item.ColumnWidth;
                    }
                    if (item.Alignment != DataGridViewContentAlignment.NotSet)
                    {
                        dgvCol.DefaultCellStyle.Alignment = item.Alignment;
                    }
                    if (item.AutoSizeMode != DataGridViewAutoSizeColumnMode.NotSet)
                    {
                        dgvCol.AutoSizeMode = item.AutoSizeMode;
                    }

                    GridView.Columns.Add(dgvCol);
                }

                if (GridView.Columns.Count == 0) return;
                GridView.DataSource = data;
                GridView.Tag = tb;
                GridView.Parent = tb.FindForm();
                GridView.BringToFront();
                GridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
                GridView.Top = GetTop(tb) + tb.Height;
                GridView.Left = GetLeft(tb);
                GridView.AutoResizeColumns();
                // GridView.AutoResizeColumnHeadersHeight();
            }
            else
            {
                if (txtArg.LocationChanged)
                {
                    GridView.Top = GetTop(tb) + tb.Height;
                    GridView.Left = GetLeft(tb);
                    txtArg.LocationChanged = false;
                }
                GridView.DataSource = data;
            }
            GridView.Visible = true;

            int newWidth = 0;
            for (int i = 0; i < GridView.Columns.Count; i++)
            {
                if (GridView.Columns[i].Visible)
                    newWidth = newWidth + GridView.Columns[i].Width + 1;
            }
            //最多显示行的数量
            int showRowCount = txtArg.MaxRowCount;
            if (showRowCount > GridView.Rows.Count) showRowCount = GridView.Rows.Count;
            if (GridView.Rows.Count > showRowCount)
            {
                GridView.ScrollBars = ScrollBars.Vertical;
                GridView.Width = newWidth + 20; //加上进度条的宽    
            }
            else
            {
                GridView.Width = newWidth;
                if (txtArg.Columns.Count(s => s.IsVisible) == 1)
                {
                    GridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
                }
            }

            int headerHeight = GridView.Rows[0].Height; //列标题的高            
            GridView.Height = headerHeight * showRowCount + GridView.ColumnHeadersHeight + 5;
            if (GridView.Width < tb.Width)
            {
                GridView.Width = tb.Width;
            }

            var frm = GridView.Parent;

            if (GridView.Width > frm.Width - GridView.Left)
            {
                //右侧超出窗体范围 与文本框右侧对齐
                GridView.Left -= GridView.Width - tb.Width;
            }

            if (GridView.Height > frm.Height - GridView.Top - tb.Height)
            {
                //下超出窗体范围 Grid在文本上方显示
                GridView.Top -= tb.Height + GridView.Height;
            }

            if (GridView.Width > frm.Width)
            {
                //如果GridView 的宽大于窗体,那么设置宽度比窗体略小 并改变位置
                GridView.Width = frm.Width - 20;// 留20间隔
                GridView.Left = 10;
            }

            if (GridView.Height > frm.Height)
            {
                //如果GridView 的高大于窗体, 那么设置高度比窗体略小 并改变位置
                GridView.Height = frm.Height - 20;// 留20间隔
                GridView.Top = 10;
            }

            if (GridView.Left < 5) GridView.Left = 5;
            if (GridView.Top < 5) GridView.Top = 5;
            GridView.Rows[0].Selected = false;
            //GridView.Focus();
        }
        /// <summary>
        /// 初始化ComboxGrid 
        /// </summary>
        public void InitArgs(params ComboxGridArgs[] args)
        {
            if (args == null) return;
            foreach (var item in args)
            {
                CGArgDict[item.TxtBox] = item;
                RegisterTextBoxEvent(item.TxtBox);
            }
            InitGridView();
        }
        /// <summary>
        /// 初始化控件,清空所有内容
        /// </summary>
        public void Clear()
        {
            GridView = null;
            CGArgDict.Clear();
        }
        /// <summary>
        /// 获取指定控件的配置参数
        /// </summary>
        public ComboxGridArgs GetConfigArg(EditText txt)
        {
            return CGArgDict[txt];
        }
    }
}